package net.ib.mtalk.ui.attachment.sound;

import java.io.File;
import java.io.IOException;

import net.ib.mtalk.constant.AttachmentConstant;
import net.ib.mtalk.util.MTalkLogWriter;
import android.media.MediaRecorder;

/**
 * MediaRecorder를 간단하게 사용하기 위한 래핑. 소리 녹음을 한다.
 * 이상한 동작을 요구하면 아무 것도 하지 않음.
 * @author Arngard
 *
 */
public class AudioRecordManager {

	private String targetPath;
	private MediaRecorder recorder = new MediaRecorder();

	/**
	 * State of state machine for this recorder. 상태 플래그.
	 * 각 상태에 따라 버튼의 동작이 결정되어야 한다.
	 * @author Arngard
	 */
	public static enum State {
		/**	아직 리소스가 준비되지 않았다. */
		BEFORE_START,
		/** 리소스가 준비되어, 이제 즉시 녹음을 시작할 수 있다. */
		READY_TO_START,
		/** 녹음이 시작되었다. */
		RECORDING,
		/** 녹음이 종료되었고 결과 처리를 하고 있다. 추가 작업은 이루어지지 않을 것이다. */
		TERMINATED
	}
	/** 현재 상태를 나타냄 */
	private State currentState = State.BEFORE_START;
	/**
	 * @return 현재의 상태
	 */
	public State getState() {
		return currentState;
	}

	/**
	 * {@link #startRecorder()}를 할 수 있도록 준비한다.
	 * @param path 다음 녹음을 할 때 기록할 파일의 경로.
	 * @throws IOException 리소스 초기화에 실패했다. 경로에 문제가 있지 않은지?
	 */
	synchronized public void resetRecorder(String path) throws IOException {
		if (currentState == State.BEFORE_START) {
			try {
				// reset the recorder
				recorder.reset();
			} catch(Exception e) {
				MTalkLogWriter.e(e);
			}
		} else if (currentState == State.READY_TO_START) {
			return;
		} else if (currentState == State.RECORDING) {
			try {
				recorder.reset();//recorder.stop();
				new File(targetPath).delete();	// targetPath에 저장되었을 녹음 파일을 삭제한다.
			} catch(Exception e) {
				MTalkLogWriter.e(e);
			}
		} else if (currentState == State.TERMINATED) {
			return;
		}

		try {
			// configure the recorder
			configRecorderLight(path);

			targetPath = path;

			// now it is prepared
			recorder.prepare();

			currentState = State.READY_TO_START;
			MTalkLogWriter.i(this.getClass().getSimpleName()+".resetRecorder(): success");
		} catch (IllegalStateException e) {
			MTalkLogWriter.e(e);
		}
	}

	/**
	 * 녹음이 시작된다.
	 * {@link #resetRecorder(String)} 혹은 {@link #stopRecorder()}을 할 수 있다.
	 */
	synchronized public void startRecorder() {
		if (currentState == State.BEFORE_START) {
			return;
		} else if (currentState == State.READY_TO_START) {
			// continue
		} else if (currentState == State.RECORDING) {
			return;
		} else if (currentState == State.TERMINATED) {
			return;
		}

		try {
			recorder.start();

			currentState = State.RECORDING;
			MTalkLogWriter.i(this.getClass().getSimpleName()+".startRecorder(): success");
		} catch (IllegalStateException e) {
			MTalkLogWriter.e(e);
		}
	}

	/**
	 * 녹음이 끝났다. 결과 처리를 한다.
	 * @return 녹음이 저장된 파일 경로.
	 */
	synchronized public String stopRecorder() {
		if (currentState == State.BEFORE_START) {
			currentState = State.TERMINATED;
			return null;
		} else if (currentState == State.READY_TO_START) {
			MTalkLogWriter.i(this.getClass().getSimpleName()+".stopRecorder(): goto cancelRecorder()");
			cancelRecorder();
			return null;
		} else if (currentState == State.RECORDING) {
			// continue
		} else if (currentState == State.TERMINATED) {
			return null;
		}

		try {
			recorder.reset();//recorder.stop();
			recorder.release();

			currentState = State.TERMINATED;
			MTalkLogWriter.i(this.getClass().getSimpleName()+".stopRecorder(): success");
			return targetPath;
		} catch (IllegalStateException e) {
			MTalkLogWriter.e(e);
		}
		return null;
	}

	/**
	 * 녹음을 하지 않고 그냥 나가려 한다. 파일 찌꺼기를 지우고 자원을 반납한다. 
	 */
	synchronized public void cancelRecorder() {
		if (currentState == State.BEFORE_START) {
			currentState = State.TERMINATED;
			return;
		} else if (currentState == State.READY_TO_START) {
			// continue
		} else if (currentState == State.RECORDING) {
			// continue
		} else if (currentState == State.TERMINATED) {
			return;
		}

		try {
			recorder.reset();
			recorder.release();

			new File(targetPath).delete();	// targetPath에 저장되었을 녹음 파일을 삭제한다.

			currentState = State.TERMINATED;
			MTalkLogWriter.i(this.getClass().getSimpleName()+".cancelRecorder(): success");
		} catch(Exception e) {
			MTalkLogWriter.e(e);
		}
	}

	@Override
	protected void finalize() throws Throwable {
		// 반드시 장치 리소스를 반납해야 한다.
		cancelRecorder();

		super.finalize();
	}

	private void configRecorderLight(String path) {
		try {
			recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
		} catch(Exception e) {
			recorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);
		}
		try {
			recorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
		} catch(Exception e) {
			recorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);
		}
		try {
			recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
		} catch(Exception e) {
			recorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
		}
		recorder.setOutputFile(path);
		recorder.setMaxDuration(AttachmentConstant.RECORD_MAX_DURATION_MILLIS);
	}
}
